package com.hex.ds.hdtp.core.app.license.activation.dto;

import cn.hutool.core.io.FileUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.Objects;

@Slf4j
@Component
public class RsaUtil {

    // RSA公钥存储路径
    @Value("${trueLicense.rsaKeysStorePath}")
    private String rsaKeysStorePath;

    // RSA相对路径
    @Value("classpath:static/license/rsaKeystore.keystore")
    private Resource rsaKeysStoreResource;

    private static volatile RSA rsa = null;

    @PostConstruct
    private void init() {
        try {
            this.getRsa();
        } catch (Exception e) {
            log.warn("初始化RSA对象失败", e);
            throw new RuntimeException("初始化RSA对象失败", e);
        }
    }
    /**
     * @Method getEncrypt
     * @Param decryptedString 需要加密的明文
     * @Return java.lang.String 密文
     * @Description 加密
     * @Author Yin.Yang
     * @Date 2024/4/2 17:44
     * @Version V1.0
     */
    public String getEncrypt(String decryptedString) {
        try {
            return rsa.encryptHex(decryptedString, KeyType.PublicKey);
        } catch (Exception e) {
            log.warn("加密失败，请检查", e);
            throw new RuntimeException("加密过程中发生异常", e);
        }
    }

    /**
     * @Method getDecrypt
     * @Param encryptedString 需要解密的密文
     * @Return java.lang.String 明文
     * @Description 解密
     * @Author Yin.Yang
     * @Date 2024/4/2 17:45
     * @Version V1.0
     */
    public String getDecrypt(String encryptedString) {
        try {
            return rsa.decryptStr(encryptedString, KeyType.PrivateKey);
        } catch (Exception e) {
            log.warn("解密失败，请检查", e);
            throw new RuntimeException("解密过程中发生异常", e);
        }
    }

    /**
     * @Method checkTwoString
     * @Param str1
     * @Param str2
     * @Return boolean
     * @Description 验证两个String的解密数值是否相等
     * @Author Yin.Yang
     * @Date 2024/4/3 13:51
     * @Version V1.0
     */
    public boolean checkTwoKey(String key1, String key2) {
        try {
            RsaUtil rsaUtil = new RsaUtil();
            String decryptValue1 = rsaUtil.getDecrypt(key1);
            String decryptValue2 = rsaUtil.getDecrypt(key2);
            return Objects.equals(decryptValue1, decryptValue2);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @Method getRsa
     * @Param
     * @Return cn.hutool.crypto.asymmetric.RSA
     * @Description DCL生成单例RSA对象
     * @Author Yin.Yang
     * @Date 2024/4/2 17:41
     * @Version V1.0
     */
    public RSA getRsa() throws Exception {
        if (rsa == null) {
            synchronized (RsaUtil.class) {
                if (rsa == null) {
                    FileUtil.copy(rsaKeysStoreResource.getFile(), new File(rsaKeysStorePath), true);
                    String keyStorePassword = "storepassword";
                    String alias = "rsaKey";
                    String keyPassword = "keypassword";
                    PublicKey publicKey = getPublicKey(rsaKeysStorePath, keyStorePassword, alias);
                    PrivateKey privateKey = getPrivateKey(rsaKeysStorePath, keyStorePassword, alias, keyPassword);
                    rsa = new RSA(privateKey, publicKey);
                }
            }
        }
        return rsa;
    }

    /**
     * @Method getPublicKey
     * @Param keyStorePath 密钥库路径
     * @Param keyStorePassword 密钥库密码
     * @Param alias 密钥别名
     * @Return java.security.PublicKey
     * @Description 从RSA密钥库中获取公钥
     * @Author Yin.Yang
     * @Date 2024/4/2 17:32
     * @Version V1.0
     */
    public static PublicKey getPublicKey(String keyStorePath, String keyStorePassword, String alias) throws Exception {
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        try (FileInputStream fis = new FileInputStream(keyStorePath)) {
            keyStore.load(fis, keyStorePassword.toCharArray());
        }
        Certificate cert = keyStore.getCertificate(alias);
        return cert.getPublicKey();
    }

    /**
     * @Method getPrivateKey
     * @Param keyStorePath 密钥库路径
     * @Param keyStorePassword 密钥库密码密
     * @Param alias 密钥别名
     * @Param keyPassword 钥密码
     * @Return java.security.PrivateKey
     * @Description 从密钥库中获取私钥
     * @Author Yin.Yang
     * @Date 2024/4/2 17:33
     * @Version V1.0
     */
    private static PrivateKey getPrivateKey(String keyStorePath, String keyStorePassword, String alias, String keyPassword) throws Exception {
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        try (FileInputStream fis = new FileInputStream(keyStorePath)) {
            keyStore.load(fis, keyStorePassword.toCharArray());
        }
        Key key = keyStore.getKey(alias, keyPassword.toCharArray());
        if (key instanceof PrivateKey) {
            return (PrivateKey) key;
        }
        throw new Exception("获取私钥失败");
    }

}
